#!/usr/bin/python
# -*- coding:utf-8 -*-
import hashlib
from random import Random
import datetime
from model.Mysql import Mysql
from model.config import static_salt
from model.models import User, Role, Level, UserRole, Incompatible, Authority, RoleAuthority, Admin, RLog, AppLog

adminToken = {}
userToken = {}
session = Mysql().getSession()
time = datetime.datetime


def adminLogin(username, password):
    user = session.query(Admin).filter_by(username=username).first()
    if user is not None:
        if user.password == hashlib.md5(static_salt + password + user.salt).hexdigest():
            token = hashlib.md5(username + user.salt).hexdigest()
            userToken[username] = token
            return {'token': token}
    return None


def adminCheckLogin(username, token):
    if username in userToken.keys():
        if adminToken[username] == token:
            return True
    return False


def login(username, password):
    user = session.query(User).filter_by(username=username).first()
    if user is not None:
        if user.password == hashlib.md5(static_salt + password + user.salt).hexdigest():
            token = hashlib.md5(username + user.salt).hexdigest()
            userToken[username] = token
            applog = AppLog(username, 1, time.now())
            session.add(applog)
            session.commit()
            return {'username': username, 'token': token}
    return None


def checkLogin(username, token):
    if username in userToken.keys():
        if userToken[username] == token:
            return True
    return False


def logout(username):
    userToken.pop(username)
    applog = AppLog(username, 2, time.now())
    session.add(applog)
    session.commit()


def addUser(username, password):
    count = session.query(User).filter_by(username=username).count()
    if count == 0:
        salt = randomStr(10)
        md5word = hashlib.md5(static_salt + password + salt).hexdigest()
        user = User(username=username, password=md5word, salt=salt)
        session.add(user)
        log = RLog('users', 1, 'username=' + username + ',password=' + md5word + ',salt=' + salt, time.now())
        session.add(log)
        session.commit()
        return True
    return False


def randomStr(saltLength):
    str = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(saltLength):
        str += chars[random.randint(0, length)]
    return str


def deleteUser(userId):
    user = session.query(User).filter_by(id=userId).first()
    for instance in user.userRole:
        session.delete(instance)
    session.delete(user)
    log = RLog('users', 2, 'useId=' + userId, time.now())
    session.add(log)
    session.commit()


def addRole(name, content):
    count = session.query(Role).filter_by(name=name).count()
    if count == 0:
        role = Role(name=name, content=content)
        session.add(role)
        log = RLog('roles', 1, 'name=' + name + ',content=' + content, time.now())
        session.add(log)
        session.commit()
        return True
    return False


def setLevel(high_id, low_id):
    if high_id == low_id:
        return False
    level = session.query(Level)
    queue = [low_id]
    while queue:
        for instance in level.filter_by(high_id=queue.pop(0)):
            if instance.low_id == high_id:
                return False
            else:
                queue.append(instance.low_id)
    level = Level(high_id=high_id, low_id=low_id)
    session.add(level)
    log = RLog('levels', 1, 'high_id=' + high_id + ',low_id=' + low_id, time.now())
    session.add(log)
    session.commit()
    return True


def getLowIdAndRoleByHighId(highId):
    result = []
    for instance in session.query(Level).filter_by(high_id=highId).all():
        result.append({'id': instance.low.id, 'name': instance.low.name})
    return result


def deleteRole(roleId):
    role = session.query(Role).filter_by(id=roleId).first()
    highInclude = []
    lowInclude = []
    for instance in session.query(Level).filter_by(low_id=roleId).all():
        highInclude.append(instance.high_id)

    for instance in session.query(Level).filter_by(high_id=roleId).all():
        print 'low'
        print instance.low_id
        lowInclude.append(instance.low_id)

    for high in highInclude:
        for low in lowInclude:
            level = Level(high, low)
            session.add(level)

    for instance in session.query(UserRole).filter_by(role_id=roleId):
        session.delete(instance)

    for instance in session.query(RoleAuthority).filter_by(role_id=roleId):
        session.delete(instance)

    for instance in session.query(Level).filter_by(low_id=roleId).all():
        session.delete(instance)

    for instance in session.query(Level).filter_by(high_id=roleId).all():
        session.delete(instance)

    session.delete(role)
    log = RLog('roles', 2, 'roleId=' + roleId, time.now())
    session.add(log)
    session.commit()


def setRole(userId, roleId):
    roles = session.query(UserRole).filter_by(user_id=userId)
    incompatibles = []
    for instance in session.query(Incompatible.another_id).filter_by(one_id=roleId).all():
        incompatibles.append(instance.another_id)
    for instance in session.query(Incompatible.one_id).filter_by(another_id=roleId).all():
        incompatibles.append(instance.one_id)
    print incompatibles
    for instance in roles:
        if instance.role_id == int(roleId):
            return False
        if instance.role_id in incompatibles:
            return False
    userRole = UserRole(userId, roleId)
    session.add(userRole)
    log = RLog('users_roles', 1, 'user_id=' + userId + ',role_id=' + roleId, time.now())
    session.add(log)
    session.commit()
    return True


def deleteLevel(highId, lowId):
    level = session.query(Level).filter_by(high_id=highId).filter_by(low_id=lowId).first()
    session.delete(level)
    log = RLog('levels', 2, 'highId=' + highId + ',lowId=' + lowId, time.now())
    session.add(log)
    session.commit()


def addAuthority(name):
    exist = session.query(Authority).filter_by(name=name).first()
    if exist is not None:
        return False
    authority = Authority(name=name)
    session.add(authority)
    log = RLog('authorities', 1, 'name=' + name, time.now())
    session.add(log)
    session.commit()
    return True


def setAuthority(roleId, authorityId):
    authority = session.query(Authority).filter_by(id=authorityId).first()
    if authority.name in getAuthoritiesByRoleId(roleId):
        return False;
    roleAuthority = RoleAuthority(roleId, authorityId)
    session.add(roleAuthority)
    log = RLog('roles_authorities', 1, 'role_id=' + roleId + ',authority_id=' + authorityId, time.now())
    session.add(log)
    session.commit()
    return True


def deleteRoleAuthority(roleId, authorityId):
    authority = session.query(RoleAuthority).filter_by(role_id=roleId).filter_by(authority_id=authorityId).first()
    print authority.id
    session.delete(authority)
    log = RLog('roles_authorities', 2, 'roleId=' + roleId + ',authorityId=' + authorityId, time.now())
    session.add(log)
    session.commit()


def deleteAuthority(authorityId):
    authority = session.query(Authority).filter_by(id=authorityId).first()
    for instance in authority.roleAuthority:
        session.delete(instance)
    session.delete(authority)
    log = RLog('authorities', 2, 'authorityId=' + authorityId, time.now())
    session.add(log)
    session.commit()


def addIncompatible(oneId, anotherId):
    if oneId == anotherId:
        return False
    roleIds = []
    for instance in session.query(Incompatible.another_id).filter_by(one_id=oneId).all():
        roleIds.append(instance.another_id)
    for instance in session.query(Incompatible.one_id).filter_by(another_id=oneId).all():
        roleIds.append(instance.one_id)
    if anotherId in roleIds:
        return False
    incompatible = Incompatible(one_id=oneId, another_id=anotherId)
    session.add(incompatible)
    log = RLog('incompatibles', 1, 'one_id=' + oneId + ',another_id=' + anotherId, time.now())
    session.add(log)
    session.commit()
    return True


def getIncompatibles():
    result = []
    for instance in session.query(Incompatible).all():
        result.append({'one_id': instance.one_id, 'one_name': instance.one.name, 'another_id': instance.another_id,
                       'another_name': instance.another.name})
    return result


def setIncompatibles(oneId, anotherId):
    result = []
    if oneId == anotherId:
        return False
    for instance in session.query(Incompatible).filter_by(one_id=oneId).all():
        result.append(instance.another_id)
    for instance in session.query(Incompatible).filter_by(another_id=anotherId).all():
        result.append(instance.one_id)
    print result
    if int(anotherId) in result:
        return False
    incompatible = Incompatible(oneId, anotherId)
    session.add(incompatible)
    log = RLog('incompatibles', 1, 'one_id=' + oneId + ',another_id=' + anotherId, time.now())
    session.add(log)
    session.commit()
    return True


def getIdAndRoles():
    result = []
    for instance in session.query(Role).all():
        result.append({'id': instance.id, 'name': instance.name, 'content': instance.content,
                       'own': getOwnAuthoritiesByRoleId(instance.id),
                       'inherit': getInheritAuthoritiesByRoleId(instance.id)})
    return result


def getIdAndRolesByUserId(userId):
    result = []
    for instance in session.query(UserRole).filter_by(user_id=userId).all():
        result.append({'id': instance.role.id, 'name': instance.role.name, 'content': instance.role.content,
                       'authorities': getIdAndAuthoritiesByRoleId(instance.role.id)})
    return result


def getIdAndUsers():
    result = []
    for instance in session.query(User).all():
        result.append({'id': instance.id, 'username': instance.username, 'roles': getRolesByUserId(instance.id),
                       'authorities': getAuthoritiesByUserId(instance.id)});
    return result


def getIdAndAuthorities():
    result = []
    for instance in session.query(Authority).all():
        result.append({'id': instance.id, 'name': instance.name})
    return result


def getIdAndAuthoritiesByRoleId(roleId):
    result = []
    for instance in session.query(RoleAuthority).filter_by(role_id=roleId).all():
        result.append({'id': instance.authority.id, 'name': instance.authority.name})
    return result


def getIdAndAuthoritiesByUsername(username):
    user = session.query(User).filter_by(username=username).first()
    roles = getIdAndRolesByUserId(user.id)
    authority = []
    for instance in roles:
        authority.extend(getIdAndAuthoritiesByRoleId(instance['id']))
    return authority


def getAuthoritiesByRoleId(roleId):
    result = []
    roleQueue = [];
    queue = [roleId];
    while queue:
        first = queue.pop(0)
        roleQueue.append(first)
        for instance in session.query(Level).filter_by(high_id=first).all():
            queue.append(instance.low_id)
    while roleQueue:
        first = roleQueue.pop(0)
        for instance in session.query(RoleAuthority).filter_by(role_id=first).all():
            result.append(instance.authority.name);
    return result


def getRolesByUserId(userId):
    result = []
    for instance in session.query(UserRole).filter_by(user_id=userId).all():
        result.append(instance.role.name)
    return result


def getAuthoritiesByRoleName(roleName):
    role = session.query(Role).filter_by(name=roleName).first()
    return getAuthoritiesByRoleId(role.id)


def getAuthoritiesByUserId(userId):
    result = []
    roles = getRolesByUserId(userId)
    for instance in roles:
        result = list(set(result + getAuthoritiesByRoleName(instance)))
    return result


def getOwnAuthoritiesByRoleId(roleId):
    result = []
    for instance in session.query(RoleAuthority).filter_by(role_id=roleId).all():
        result.append(instance.authority.name)
    return result


def getInheritAuthoritiesByRoleId(roleId):
    result = []
    roleQueue = [];
    queue = [roleId];
    while queue:
        first = queue.pop(0)
        roleQueue.append(first)
        for instance in session.query(Level).filter_by(high_id=first).all():
            queue.append(instance.low_id)
    roleQueue.pop(0)
    while roleQueue:
        first = roleQueue.pop(0)
        for instance in session.query(RoleAuthority).filter_by(role_id=first).all():
            result.append(instance.authority.name);
    return list(set(result))


def getIdAndUserByUsername(username, appFlag):
    user = session.query(User).filter_by(username=username).first()
    roles = []
    authority = []
    for instance in session.query(Role).filter_by(app_flag=appFlag).all():
        roles.append(instance.name)
        authority = getAuthoritiesByRoleId(instance.id) + authority
    authority = list(set(authority))

    return {'id': user.id, 'username': user.username,
            'roles': list(set(getRolesByUserId(user.id)).intersection(set(roles))),
            'authorities': list(set(getAuthoritiesByUserId(user.id)).intersection(set(authority)))}


def checkSize(tablename, size):
    if tablename == 'rlogs':
        if size <= session.query(RLog).count():
            return True
        return False
    elif tablename == 'applogs':
        if size <= session.query(AppLog).count():
            return True
        return False
    return False


def getRBACLogs(size=1000, operation=0):
    result = []
    if operation == 0:
        for instance in session.query(RLog).order_by(RLog.time.desc()):
            result.append(
                {'tablename': instance.tablename, 'operation': instance.operation, 'content': instance.content,
                 'time': instance.time.strftime('%Y-%m-%d %H-%M-%S')})
    else:
        for instance in session.query(RLog).filter_by(operation=operation).order_by(RLog.time.desc()):
            result.append(
                {'tablename': instance.tablename, 'operation': instance.operation, 'content': instance.content,
                 'time': instance.time.strftime('%Y-%m-%d %H-%M-%S')})
    return {'result': checkSize('rlogs', size), 'logs': result}


def getAppLogs(size=1000, operation=0):
    result = []
    if operation == 0:
        for instance in session.query(AppLog).order_by(AppLog.time.desc()):
            result.append(
                {'username': instance.username, 'operation': instance.operation,
                 'time': instance.time.strftime('%Y-%m-%d %H-%M-%S')})
    else:
        for instance in session.query(AppLog).filter_by(operation=operation).order_by(AppLog.time.desc()):
            result.append({'username': instance.username, 'operation': instance.operation,
                           'time': instance.time.strftime('%Y-%m-%d %H-%M-%S')})
    return {'result': checkSize('rlogs', size), 'logs': result}


def deleteLogs(tablename, time):
    if tablename == 'rlogs':
        for instance in session.query(RLog).filter('time > :time').params(time=time).all():
            print instance.id
            session.delete(instance)
    elif tablename == 'applogs':
        for instance in session.query(AppLog).filter('time > :time').params(time=time).all():
            session.delete(instance)
    session.commit()